/***************************************************************************
 *   Copyright (C) 2007 by Grzegorz Latarowski   *
 *   g.latarowski@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#ifndef GRAPH_H
#define GRAPH_H


// Qt
#include <QtGui>

class GNode;


// ------------------------------ GGraph{} -----------------------------------
/// \class GGraph
/// \brief Base class for all graphicsItem that uses nodes.
// ---------------------------------------------------------------------------
class GGraph : public QObject, public QGraphicsItem
{
	Q_OBJECT
public:

	// ====================================================
	// contructor
	
	/// \brief Construct GGraph objcet.
	/// Copies params to QGraphicsItem constructorl
	GGraph( QGraphicsItem * pParent = 0, QGraphicsScene * pScene = 0 )
		: QGraphicsItem( pParent, pScene ) {}

	// ====================================================
	// item manipulation 
	
	/// \brief Adjust object.
	///
	/// This pure virtual function is called by each items node everytime
	/// that node was changed.
	virtual void adjust() = 0;

	/// \brief Return objects color.
	///
	/// This pure virtual function is called whenever items node repaints.
	virtual QColor color() const = 0;

	/// \brief Adds node to graph item.
	///
	/// New node is inserted on the and of all items nodes,
	/// into position \a position.
	virtual void addNode( const QPointF & /*position*/ ) {}

	/// \brief Adds node to graph item.
	///
	/// New now is inserted after \a previousNode into position \a position.
	virtual void addNode( GNode * /*previousNode*/,  const QPointF & /*position*/ ) {}

	/// \brief Removes node \a node.
	///
	/// If items nodes are removable than can call this method
	/// to remove themselves.
	virtual void removeNode( GNode * /*node*/ ) {}

	/// \brief Returns items name.
	QString name()const { return _name; }

	/// \brief Sets items name. 
	void setName( const QString & name ) { _name = name; }

signals:
	/// \brief Should be emitted whenever items nodes position changed.
	void itemChanged();
	
private:
	QString _name; ///< Items name

}; // class !GGraph
// ---------------------------------------------------------------------------





// ------------------------------- GNode{} -----------------------------------
/// \brief Represents a node on graphicsScene.
///
/// Class delivers node item with abilities to move around the bound of
/// scenes rect. After its moved it calls parent to update its position.
/// It can call its parent to delete this node, if removeable flag is set.
/// It paints itself with a colors based on one getted from its parent.
/// GGraph inherited object need to be its parent.
// ---------------------------------------------------------------------------
class GNode : public QObject, public QGraphicsItem
{
	Q_OBJECT

public:

	// ====================================================
	// constructor

	/// \brief Creates node item.
	///
	/// Sets nodes parent graph \e _pGraph to \a pGraph, sets \e _removable flag
	/// to \a removable, by default node isn't removable.
	GNode( GGraph * pGraph, bool removable = false );

	// ====================================================
	// node setups 

	/// \brief Set \e _removable flag to \a removable.
	void setRemovable( const bool removable ) { _removable = removable; }

	/// \brief Returns items \a removable flag. 
	bool removable()const { return _removable; }

	/// \brief Sets QPainterpath which is used to render the item.
	///
	/// At default it is QRect( -5, -5, 10, 10 ).
	void setShape( const QPainterPath & shape ) { _shape = shape; }

	// ====================================================
	// QGraphicsItem specific 

	/// \brief Returns items bounding rect. 
	virtual QRectF boundingRect() const;

	/// \brief Returns items shape. 
	virtual QPainterPath shape() const;

	/// \brief Paints the item. 
	virtual void paint( QPainter * pPainter,
						const QStyleOptionGraphicsItem * pOption,
						QWidget * pWidget );

private slots:
	/// \brief Gets \e _removeAction signals and calls \e _pGraph to remove it. 
	void removeNode();

protected:
	/// \brief Creates context menu with \e _removeAction if _removable flag is set.
	virtual void contextMenuEvent( QGraphicsSceneContextMenuEvent * event );

	/// \brief Take cares of keeping nodes inside its scene rect.
	///
	/// Calls parent graph item to update its position. 
	virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);

	/// \brief Take cares of keeping node inside its scene rect after node
	/// was moved manualy.
	///
	/// Calls parent graph item to update its position. 
	virtual void mouseMoveEvent( QGraphicsSceneMouseEvent * event );

	/// \brief Changes mouse cursor when items is catched. 
	virtual void mousePressEvent( QGraphicsSceneMouseEvent * event);

	/// \brief Changes mouse cursor when imte is released. 
	virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent * event);

private:
	bool           _removable;    ///< Idicates if node is removable
	GGraph       * _pGraph;       ///< Pointer to nodes parent graph 
	QAction      * _removeAction; ///< An instance of remove action
	QPainterPath   _shape;        ///< Shape used to render node

}; // class !GNode
// ---------------------------------------------------------------------------





// --------------------------- GEdge{} ---------------------------------------
/// \brief Represents and edge between two nodes in the graph item.
///
/// It paints an edge between nodes. If edge is clickable after click it
/// class graph parent to add new node.
// ---------------------------------------------------------------------------
class GEdge : public QObject, public QGraphicsItem
{
	Q_OBJECT

public:

	// ====================================================
	// constructor

	/// \brief Constructs edge item.
	GEdge( GGraph * pGraph, GNode * pNode1, GNode * pNode2,
		   const bool clickable = true );

	// ====================================================
	// edge stup
	
	/// \brief Set edge clickable flag \e _clickable to \a clickable.
	///
	/// It changes mouse over cursor to indicate if item is clickable or not.
	void setClickable( const bool clickable );

	/// \brief Returns edge clickable flag.
	bool clickable() { return _clickable; }

	// ====================================================
	// QGraphics specific 

	/// \brief Returns edge boundign rect. 
	virtual QRectF boundingRect() const;

	/// \brief Returns edge shape.
	virtual QPainterPath shape() const;

	/// \brief Paints the edge line.
	virtual void paint( QPainter * pPainter,
						const QStyleOptionGraphicsItem * pOption,
						QWidget * pWidget );

	/// \brief Adjust edge position after nodes was moved.
	void adjust();

protected:
	/// \brief Calls graph parent \e _pGraph to add new
	/// node if _clickable flag is set.
	virtual void mouseDoubleClickEvent( QGraphicsSceneMouseEvent * event );

private:
	GGraph * _pGraph; ///< Pointer to edge parent graph
	GNode  * _pNode1; ///< Pointer to starting node item 
	GNode  * _pNode2; ///< Pointer to ending node item 

	bool _clickable;  ///< This flag indicates if item is clickable 
	
	QPointF _start;  ///< Holds \e _pNode1 position 
	QPointF _end;    ///< Holds \e _pNode2 position 

}; // class !GEdge
// ---------------------------------------------------------------------------






#endif // !GRAPH_H

// eof
